package com.azt.front.servlet;

import com.azt.api.pojo.Company;
import com.azt.api.pojo.PinganAccount;
import com.azt.api.pojo.PinganAmountIn;
import com.azt.api.pojo.PinganAmountOut;
import com.azt.api.service.*;
import com.azt.exception.BaseException;
import com.azt.provider.utils.BankInterface;
import com.azt.utils.BeanUtils;
import com.azt.utils.DESUtils;
import com.azt.utils.MyStringUtils;
import com.xiaoleilu.hutool.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.HashMap;

public class MessageHandler extends Thread{

	public static final String RSP_SUCC_CODE = "000000";//默认交易成功应答码
	private static final String RSP_SUCC_MSG = "交易成功";//默认交易 成功应答描述
	private static final String CODE_UNDEFINED = "ERR935";//交易码不存在
	private static final String NO_RECORD = "ERR020";//记录不存在
	private static final String ERROR_FUNCTION = "ERR021";//错误的功能码
	private static final String ERROR_COMPANY = "ERR093";//交易网会员代码输入错误
	private static final String AZT_ERROR = "ERR091";//交易网返回失败描述


	private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

    public static Logger logger = LoggerFactory.getLogger("paInfo");
	public static Logger loggerError = LoggerFactory.getLogger("paError");


	Socket mSocket = null;
	boolean mStopped = false;
	BufferedWriter mWriter = null;
	BufferedReader mReader = null;


	private BankInterface msg = new BankInterface();

//	public MessageHandler(){}

	/**
	 * 创建新的消息处理器
	 * @param pSocket
	 */
	public MessageHandler(Socket pSocket)
	{
		logger.info("创建新的消息处理器");
		mSocket = pSocket;
	}

	//打开并监听socket
	public void run()
	{
		char tagChar[];
		tagChar = new char[1024];
		int len;
		String temp;
		String rev = "";
		try {
			while (! mStopped && ! mSocket.isClosed()) {
				logger.info("处理消息...");
				mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream() , "gbk"));
				mWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream() , "gbk"));

				if ((len = mReader.read(tagChar)) != -1) {
					temp = new String(tagChar, 0, len);
					rev += temp;
					temp = null; }
				handleMessage(rev,mWriter);
				closeSocket();
			}
		} catch (Exception e) {
			loggerError.error("error in MessageHandler -- closing down.错误：" , e);
			e.printStackTrace();
		}

	}

	/**
	 * 处理接收到的消息
	 * @param pMessage
	 * @throws java.io.IOException
	 */
	public void handleMessage(String pMessage, BufferedWriter bwriter) throws java.io.IOException
	{
		logger.info("进入消息处理方法...");
		logger.info("报文："+pMessage);

		if (StrUtil.isBlank(pMessage)) {
			bwriter.write("");
			bwriter.flush();
			bwriter.close();
			return;
		}

		HashMap retKeyDict = msg.parsingTranMessageString(pMessage);//存放解析出来的请求报文的参数

//		logger.info("银行发送报文解析后：" + retKeyDict.toString());

		//读取交易码
		Integer TranFunc=Integer.parseInt(retKeyDict.get("TranFunc").toString());

		String back = "";

		switch (TranFunc){
			case 1303 : back = getBackMessage_1303(retKeyDict);break;//签约解约
			case 1310 : back = getBackMessage_1310(retKeyDict);break;//银行发起入金
			case 1312 : back = getBackMessage_1312(retKeyDict);break;//银行发起出金
			case 1019 : back = getBackMessage_1019(retKeyDict);break;//银行查交易网会员余额
			case 1326 : back = getBackMessage_1326(retKeyDict);break;//复核支付银行通知回调
		}

		bwriter.write(back +"\r\n");
		bwriter.flush();
		bwriter.close();
	}

	public static void main(String[] args) {
//		MessageHandler mh = new MessageHandler();
//		try {
//			mh.handleMessage("A0010301018981                0000000283000000EB001012017022019304217022058457746      999999                                                                                                    00000000000000000000000000000130301                20170220193042999999                                          000000161EB00117022058457746      89811&11005109404201&888800117391921&平安测试六零零零六四四四六五九九&1483D06986093541&52&12342195-X&11014847233002&3&1&平安测试六零零零六四四四六五九九&&平安银行&&&" , null);
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		try {
//			String bw=" 20170217102427ERR091绛捐妭绾﹀け璐ワ細";
//			byte[] a = bw.getBytes("GBK");
//			String sss=new String(a,"UTF-8");
//			System.out.println( sss );
//		} catch (UnsupportedEncodingException e) {
//			e.printStackTrace();
//		}
	}

	/**
	 * 银行端签解约
	 * @param retKeyDict
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getBackMessage_1303(HashMap retKeyDict) throws UnsupportedEncodingException {

		logger.info("进入签解约方法...");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
		CompanyService companyService = (CompanyService) ctx.getBean("companyServiceImpl");
		PinganAccountService pinganAccountService = (PinganAccountService) ctx.getBean("pinganAccountServiceImpl");

		HashMap parmaKeyDict = new HashMap();//存放准备返回的报文参数

		//读取报文体内容
		String TranFunc = retKeyDict.get("TranFunc").toString();//交易码
		String FuncFlag=(String)retKeyDict.get("FuncFlag");//功能标志
		String ThirdCustId=(String)retKeyDict.get("ThirdCustId");//会员代码

		logger.info("签解约！ThirdCustId:" + ThirdCustId);

		String rspCode = RSP_SUCC_CODE;//应答码
		String repMsg = RSP_SUCC_MSG;//应答码描述
		String thirdLogNo = MyStringUtils.getSerialNum();//流水号

		try {
			if (StrUtil.isNotBlank(FuncFlag)) {
				String cid = DESUtils.decryptToCompanyId(ThirdCustId);
				logger.info("签解约企业id:" + cid);
				Company company = companyService.getCompanyById(Integer.parseInt(cid));//签约企业
				if (company != null) {
					PinganAccount account = pinganAccountService.getValidAccountByCompanyId(company.getId());
					if ("1".equals(FuncFlag)) {//功能是指定时
						if (company.getSignPingan().compareTo(1) == 0 || account != null) {
							rspCode = ERROR_COMPANY;//已经签约了
							repMsg = "交易网会员已经签约";
						} else {//正式开始签约
							try {
								repMsg = "签约成功";
								PinganAccount pa = new PinganAccount(retKeyDict);
								pa.setCompanyId(company.getId());
								pa.setThirdLogNo(thirdLogNo);
								pa.setRspCode(rspCode);
								pa.setRspMsg(repMsg);
								pinganAccountService.insertAccount(pa);//绑定签约
							} catch (Exception e) {
//								e.printStackTrace();
								loggerError.error("签约失败" , e);
								rspCode = AZT_ERROR;//签约绑定失败
								repMsg = "签约绑定失败！";
							}
						}
					}
					if ("2".equals(FuncFlag)) {//功能是修改时
						if (account != null) {
							try {
								PinganAccount pa = new PinganAccount(retKeyDict);
								pa.setThirdLogNo(thirdLogNo);
								BeanUtils.copyBeanNotNull2Bean(pa, account, "createtime");
								account.setRspCode(rspCode);
								account.setRspMsg(repMsg);
								pinganAccountService.updateAccount(account);//更新平安账户信息
								repMsg = "签约修改成功";
							} catch (Exception e) {
//								e.printStackTrace();
								loggerError.error("修改签约失败" , e);
								rspCode = AZT_ERROR;//签约绑定失败
								repMsg = "修改签约绑定失败！";
							}
						} else {
							rspCode = AZT_ERROR;//签约绑定失败
							repMsg = "修改失败，交易网未签约绑定";
						}
					}
					if ("3".equals(FuncFlag)) {//功能是删除时
						if (account != null) {
							pinganAccountService.deleteAccount(account);
							repMsg = "解除签约成功";
						} else {
							rspCode = AZT_ERROR;//签约绑定失败
							repMsg = "销户失败，交易网未签约绑定";
						}
					}
				} else {
					rspCode = ERROR_COMPANY;//企业记录不存在
					repMsg = "交易网会员记录不存在";
				}
			} else {
				rspCode = ERROR_FUNCTION;//功能标志错误
				repMsg = "功能标志不存在";
			}
		} catch (IllegalArgumentException ie) {
			loggerError.error("签约失败，交易网会员代码有误" , ie);
			rspCode = AZT_ERROR;//功能标志错误
			repMsg = "签约失败，交易网会员代码有误";
		} catch (Exception e) {
//			e.printStackTrace();
			loggerError.error("签解约失败" , e);
			rspCode = AZT_ERROR;//功能标志错误
			repMsg = "签解约失败：" + e.getMessage();
		}


		logger.info(repMsg);


		//组返回报文
        /*报文参数赋值*/
		parmaKeyDict.put("RspCode", rspCode);//应答码
		parmaKeyDict.put("RspMsg", repMsg);//应答描述
		parmaKeyDict.put("TranFunc", TranFunc);//交易码
		parmaKeyDict.put("ThirdLogNo", thirdLogNo); //返回流水号
		parmaKeyDict.put("Reserve", "");

		String back = msg.getReturnTranMessage(parmaKeyDict);
		logger.info("back:" + back);

		return back;
	}


	/**
	 * 银行端入金回调
	 * @param retKeyDict
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getBackMessage_1310(HashMap retKeyDict) throws UnsupportedEncodingException {

		logger.info("进入银行入金回调方法...");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
		PinganAmountInService pinganAmountInService = (PinganAmountInService) ctx.getBean("pinganAmountInServiceImpl");
		PinganAccountService pinganAccountService = (PinganAccountService) ctx.getBean("pinganAccountServiceImpl");


		HashMap parmaKeyDict = new HashMap();//存放准备返回的报文参数

		//读取报文体内容
		String TranFunc = retKeyDict.get("TranFunc").toString();//交易码
		String CustAcctId = (String)retKeyDict.get("CustAcctId");//子账户id
		String CcyCode = (String)retKeyDict.get("CcyCode");//币种

		logger.info("入金子账户ID：CustAcctId:" + CustAcctId);

		String rspCode = RSP_SUCC_CODE;//应答码
		String repMsg = RSP_SUCC_MSG;//应答码描述
		String thirdLogNo = MyStringUtils.getSerialNum();//流水号

		try {
			if(StrUtil.isNotBlank(CustAcctId)){
                PinganAccount account = pinganAccountService.getAccountByCustAcctId(CustAcctId);
                if (account != null) {
                    try {
                        if(BankInterface.DEFAULT_CCY_CODE.equals(CcyCode)){
                            PinganAmountIn pai = new PinganAmountIn(retKeyDict);
                            pai.setRspCode(rspCode);
                            pai.setRspMsg(repMsg);
                            pai.setThirdLogNo(thirdLogNo);
                            pai.setAccountId(account.getId());
                            pinganAmountInService.insertAmountIn(pai);
                        }
                    } catch (Exception e) {
//                        e.printStackTrace();
						loggerError.error("银行端入金失败" , e);
                        rspCode = AZT_ERROR;//入金保存失败
                        repMsg = "入金失败";
                    }


                }else{
                    rspCode = AZT_ERROR;//交易网绑定记录不存在
                    repMsg = "交易网绑定记录不存在";
                }
            }else{
                rspCode = AZT_ERROR;//入金子账户ID未接收到
                repMsg = "入金子账户ID未接收到";
            }
		} catch (Exception e) {
//			e.printStackTrace();
			loggerError.error("银行端入金失败" , e);
			rspCode = AZT_ERROR;//功能标志错误
			repMsg = "入金失败";
		}

		logger.info(repMsg);

		//组返回报文
        /*报文参数赋值*/
		parmaKeyDict.put("RspCode", rspCode);//应答码
		parmaKeyDict.put("RspMsg", repMsg);//应答描述
		parmaKeyDict.put("TranFunc", TranFunc);//交易码
		parmaKeyDict.put("ThirdLogNo", thirdLogNo); //返回流水号
		parmaKeyDict.put("Reserve", "");

		String back = msg.getReturnTranMessage(parmaKeyDict);
		logger.info("back:" + back);

		return back;
	}


	/**
	 * 银行端发起出金
	 * @param retKeyDict
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getBackMessage_1312(HashMap retKeyDict) throws UnsupportedEncodingException {

		logger.info("进入银行出金回调方法...");

		ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
		PinganAmountOutService pinganAmountOutService = (PinganAmountOutService) ctx.getBean("pinganAmountOutServiceImpl");
		PinganAccountService pinganAccountService = (PinganAccountService) ctx.getBean("pinganAccountServiceImpl");


		HashMap parmaKeyDict = new HashMap();//存放准备返回的报文参数

		//读取报文体内容
		String TranFunc = retKeyDict.get("TranFunc").toString();//交易码
		String CustAcctId = (String)retKeyDict.get("CustAcctId");//子账户id
		String CcyCode = (String)retKeyDict.get("CcyCode");//币种

		logger.info("出金子账户ID：CustAcctId:" + CustAcctId);

		String rspCode = RSP_SUCC_CODE;//应答码
		String repMsg = RSP_SUCC_MSG;//应答码描述
		String thirdLogNo = MyStringUtils.getSerialNum();//流水号

		try {
			if(StrUtil.isNotBlank(CustAcctId)){
                PinganAccount account = pinganAccountService.getAccountByCustAcctId(CustAcctId);
                if (account != null) {
                    try {
                        if(BankInterface.DEFAULT_CCY_CODE.equals(CcyCode)) {
                            PinganAmountOut pao = new PinganAmountOut(retKeyDict);
                            pao.setRspCode(rspCode);
                            pao.setRspMsg(repMsg);
                            pao.setThirdLogNo(thirdLogNo);
                            pao.setAccountId(account.getId());
                            pinganAmountOutService.insertAmountOut(pao);
                        }
                    } catch (Exception e) {
//                        e.printStackTrace();
						loggerError.error("银行端出金失败" , e);
                        rspCode = AZT_ERROR;//入金保存失败
                        repMsg = "出金失败";
                    }


                }else{
                    rspCode = AZT_ERROR;//交易网绑定记录不存在
                    repMsg = "交易网绑定记录不存在";
                }
            }else{
                rspCode = AZT_ERROR;//入金子账户ID未接收到
                repMsg = "出金子账户ID未接收到";
            }
		} catch (Exception e) {
			loggerError.error("银行端出金失败" , e);
			rspCode = AZT_ERROR;//功能标志错误
			repMsg = "出金失败";
		}

		logger.info(repMsg);

		//组返回报文
        /*报文参数赋值*/
		parmaKeyDict.put("RspCode", rspCode);//应答码
		parmaKeyDict.put("RspMsg", repMsg);//应答描述
		parmaKeyDict.put("TranFunc", TranFunc);//交易码
		parmaKeyDict.put("ThirdLogNo", thirdLogNo); //返回流水号
		parmaKeyDict.put("Reserve", "");

		String back = msg.getReturnTranMessage(parmaKeyDict);
		logger.info("back:" + back);

		return back;
	}


	/**
	 * 银行查交易网会员余额
	 * @param retKeyDict
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getBackMessage_1019(HashMap retKeyDict) throws UnsupportedEncodingException {

		logger.info("进入查询交易网会员余额方法...");

		HashMap parmaKeyDict = new HashMap();//存放准备返回的报文参数
		ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
		PinganAccountService pinganAccountService = (PinganAccountService) ctx.getBean("pinganAccountServiceImpl");


		//读取报文体内容
		String TranFunc = retKeyDict.get("TranFunc").toString();//交易码
		String CustAcctId = (String)retKeyDict.get("CustAcctId");//子账户id

		logger.info("被查询子账户ID：CustAcctId:" + CustAcctId);

		String rspCode = RSP_SUCC_CODE;//应答码
		String repMsg = RSP_SUCC_MSG;//应答码描述
		String thirdLogNo = MyStringUtils.getSerialNum();//流水号
		String ThirdCustId = "";
		String CustName = "";
		String TotalAmount = "";
		String TotalBalance = "";
		String TotalFreezeAmount = "";
		String TranDate = "";

		if(StrUtil.isNotBlank(CustAcctId)){
			PinganAccount account = pinganAccountService.getAccountByCustAcctId(CustAcctId);
			if (account != null) {
				ThirdCustId = account.getThirdCustId();
				CustName = account.getCustName();
				Double total = (account.getTranAmount() + account.getFrozenAmount()) * 100;
				TotalAmount = String.valueOf(total.intValue());//分为单位
				Double tb = account.getTranAmount() * 100;
				TotalBalance = String.valueOf(tb.intValue());//分为单位
				Double tfa = account.getFrozenAmount() * 100;
				TotalFreezeAmount = String.valueOf(tfa.intValue());//分为单位
				TranDate = sdf.format(account.getUpdatetime());
			}else{
				rspCode = AZT_ERROR;//交易网绑定记录不存在
				repMsg = "交易网绑定记录不存在";
			}
		}else{
			rspCode = AZT_ERROR;//入金子账户ID未接收到
			repMsg = "出金子账户ID未接收到";
		}

		logger.info(repMsg);

		//组返回报文
        /*报文参数赋值*/
		parmaKeyDict.put("RspCode", rspCode);//应答码
		parmaKeyDict.put("RspMsg", repMsg);//应答描述
		parmaKeyDict.put("TranFunc", TranFunc);//交易码
		parmaKeyDict.put("ThirdLogNo", thirdLogNo); //返回流水号
		parmaKeyDict.put("CustAcctId", CustAcctId); //子账户
		parmaKeyDict.put("ThirdCustId", ThirdCustId); //交易网会员代码
		parmaKeyDict.put("CustName", CustName); //会员名称
		parmaKeyDict.put("TotalAmount", TotalAmount); //账户总余额
		parmaKeyDict.put("TotalBalance", TotalBalance); //账户可用余额
		parmaKeyDict.put("TotalFreezeAmount", TotalFreezeAmount); //账户总冻结金额
		parmaKeyDict.put("TranDate", TranDate); //维护日期
		parmaKeyDict.put("Reserve", "");

		String back = msg.getReturnTranMessage(parmaKeyDict);
		logger.info("back:" + back);

		return back;
	}

	/**
	 * 复核支付银行通知回调
	 * @param retKeyDict
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getBackMessage_1326(HashMap retKeyDict) throws UnsupportedEncodingException {


		logger.info("进入复核支付银行通知回调方法...");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
		OrderService orderService = (OrderService) ctx.getBean("orderServiceImpl");


		HashMap parmaKeyDict = new HashMap();//存放准备返回的报文参数

		//读取报文体内容
		String TranFunc = retKeyDict.get("TranFunc").toString();//交易码
		String FuncFlag = (String)retKeyDict.get("FuncFlag");//功能标志 1：支付复核
		String CheckResult = (String)retKeyDict.get("CheckResult");//复核结果 Y：复核通过	N：复核拒绝
		String CcyCode = (String)retKeyDict.get("CcyCode");//币种
		String ThirdHtId = (String)retKeyDict.get("ThirdHtId");//订单号
		String PaySerialNo = (String)retKeyDict.get("PaySerialNo");//原支付指令号

		logger.info("复核通知，订单号:" + ThirdHtId+"，指令号：" + PaySerialNo + "，通知结果："+CheckResult);

		String rspCode = RSP_SUCC_CODE;//应答码
		String repMsg = RSP_SUCC_MSG;//应答码描述
		String thirdLogNo = MyStringUtils.getSerialNum();//流水号
		retKeyDict.put("ThirdLogNo", thirdLogNo);

		if("1".equals(FuncFlag) && BankInterface.DEFAULT_CCY_CODE.equals(CcyCode)){
			try {
				orderService.auditOrderForPingan(retKeyDict);
				repMsg = "复核成功";
			} catch (BaseException e) {
				loggerError.error("交易网复核失败" , e);
				rspCode = AZT_ERROR;
				repMsg = e.getErrorCode();
			}
		}else{
			rspCode = AZT_ERROR;
			repMsg = "复核通知功能标志有误或币种非RMB";
		}

		logger.info(repMsg);

		//组返回报文
        /*报文参数赋值*/
		parmaKeyDict.put("RspCode", rspCode);//应答码
		parmaKeyDict.put("RspMsg", repMsg);//应答描述
		parmaKeyDict.put("TranFunc", TranFunc);//交易码
		parmaKeyDict.put("ThirdLogNo", thirdLogNo); //返回流水号
		parmaKeyDict.put("Reserve", "");

		String back = msg.getReturnTranMessage(parmaKeyDict);
		logger.info("back:" + back);

		return back;
	}

	/**
	 * 关闭socket.
	 */
	public void closeSocket() throws java.io.IOException
	{
		mSocket.close();
	}

	/**
	 * 停止处理器.
	 */
	void stopHandler()
	{
		mStopped = true;

		try {
			closeSocket();
		} catch (Exception e) {
			// ignore--we're stopping.
		}
	}
}
